#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class Student;
class Person
{
public:
	friend void Display( const Person& p, const Student& s);

	Person(const char* name = "Peter", int a = 10)
		:_name(name)
		,_age(10)
	{
		cout << "Person()" << endl;
		_count++;
	}

	Person(const Person& p)
		:_name(p._name)
		, _age(p._age)
	{
		cout << "Person(const Person& p)" << endl;
	}

	Person& operator=(const Person& p)
	{
		_name = p._name;
		_age = p._age;
		cout << "Person& operato=()" << endl;

		return *this;
	}
	
	~Person()
	{
		_age = 0;
		_name = "";
		cout << "~Person()" << endl;
	}

	void print()
	{
		cout << "Person:" << _name << " " << _age << endl;
	}

	static int _count;
protected:
	string _name;
	int _age;
};

int Person::_count = 0;
class Student :public Person
{
public:
	//友元函数不能继承，父类的友元函数不是子类的友元函数，要使用就需要定义友元函数
	friend void Display(const Person& p, const Student& s);

	Student(const char* name = "Wangwu", int id = 100)
		:Person(name)
		, _id(id)
	{
		cout << "Student()" << endl;
	}

	Student(const Student& s)
		:Person(s)
		, _id(s._id)
	{
		cout << "Student(const Student& s)" << endl;

	}

	Student& operator=(const Student& s)
	{
		Person::operator=(s);
		_id = s._id;
		cout << "Student& operator=()" << endl;

		return *this;
	}

	~Student()
	{
		//显示调用不能保证父类和子类的析构顺序
		//Person::~Person();
		//子类析构函数调用完成后就调用父类的析构函数，可以保证先子后父的顺序
		delete _ptr;
	}

	void print()
	{
		cout << "Student:" <<_name << " " << _age << endl;
	}

	void print(int i)
	{
		cout << "Student(int i):" << _name << " " << _age << endl;
	}

protected:
	int _id = 0;
	int* _ptr = new int(1);
};

void Display(const Person& p, const Student& s)
{
	cout << p._age << endl;
	cout << s._id << endl;
}


//隐藏/重定义 子类中有跟父类同名的成员变量或者成员函数 子类会对父类进行隐藏
void test1()
{
	Student s;
	s.print();
	//显示调用父类的成员函数
	s.Person::print();
	s.print(1);
}

void test2()
{
	Person p;
	Person p1(p);
	Person p2("zhangsan");
	p1 = p2;
}

void test3()
{
	Student s;
	Student s1(s);
	Student s2("Mike");
	s1 = s2;
}

//基类定义了static静态成员，则整个继承体系里面只有一个这样的成员。无论派生出多少个子类，都只有一个static成员实例
//统计调用了几次Person的构造函数(统计人数)
void test4()
{
	Person p;
	Student s;
	Student s2;
	Student s3;
	Student s4;

	cout << Person::_count << endl;  //5

}

class A
{
public:
	int _sa;

};

class B :virtual public A
//class B :public A
{
public:
	int _sb = 0;
};

class C :virtual public A
//class C:public A
{
public:
	int _sc = 0;
};

//多继承--菱形继承--虚拟继承--只有一份A数据
class D :public B, public C
{
public:
	int _sd = 0;
};

//菱形继承
void test5()
{
	A aa;
	B bb;
	C cc;
	D dd;

	aa._sa=1;
	bb._sa=2;
	cc._sa=3;
	//无法访问 必须指定类
	//dd._sa;
	//dd里面存有两份A的数据
	dd.B::_sa=4;
	dd.C::_sa=5;


}

//虚拟继承
void test6()
{
	A aa;
	B bb;
	C cc;
	D dd;

	aa._sa = 1;
	bb._sa = 2;
	cc._sa = 3;
	//dd中只有一份A数据
	//dd中的B对象和C对象占8个字节（32位平台下)--一个整型存储自身的数据 一个指针指向虚基表（用来存储B(C)到A的相对偏移量以及B(C)的其他数据）
	dd._sa = 4;

	//这种情况下，编译器分不清是哪种对象（单继承or菱形继承）的ptr调用的_sa，一律会按照偏移量去找A中的_sa
	B* ptr = &bb;
	ptr->_sa;

	/*B* ptr = &dd;
	ptr->_sa;*/

	//这种情况下，d要去找出B / C成员中的A才能赋值过去,这时候就需要使用虚基表中的相对偏移量
	D d;
	B b = d;
	C c = d;

}

//赋值兼容（切片，切割）
//派生类对象 可以赋值给 基类的对象 / 基类的指针 / 基类的引用 叫切片或者切割
//基类不能赋值给派生类
void test7()
{
	Student s("Lilei");
	Person pp = s;
	//ptrp指向的是s对象中继承Person的那一部分
	Person* ptrp = &s;
	Person& pr = s;

	s.print();
	pp.print();
	ptrp->print();
	pr.print();



}


int main()
{/*
	test1();
	cout << "---------------------------------" << endl;

	test2();
	cout << "---------------------------------" << endl;*/

	//test3();
	//cout << "---------------------------------" << endl;

	/*Person pp;
	Student ss;
	Display(pp,ss);*/
	

	//test4();
	//cout << "---------------------------------" << endl;

	test5();

	test6();

	test7();





	return 0;
}